﻿#pragma once
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include "common_struct.h"
#include <bitset>
#include <unordered_map>
#define HEADER "\033[95m"
#define OKBLUE "\033[94m"
#define OKGREEN "\033[92m"
#define WARNING "\033[93m"
#define FAIL "\033[91m"
#define ENDC "\033[0m"
#define BOLD "\033[1m"
#define UNDERLINE "\033[4m"
#define OK "\033[92m"
#define WARNING "\033[93m"
#define FAIL "\033[91m"  
#define RESET "\033[0m"  
#define RED_ 1
#define BLUE_ 2

using std::bitset;


//用来存放Board类
class Board
{
public:
	/*
	* parm: line 用来存放边
	* parm: box 用来存格子
	*/
	int line[2][6][5];
	int box[5][5];
	int next_turn = -1;

	Board()
	{
		memset(line, 0, sizeof line);
		memset(box, 0, sizeof box);
	}

	//设置步伐, 只有步伐合法才会被设置, 设置成功后返回true, 反之返回false, 但返回值没有用过
	bool set_line(int owner, int dir, int x, int y)
	{
		if (check_illegal({ dir, x, y }))
		{
			this->line[dir][x][y] = owner;
			return true;
		}
		return false;
	}

	//返回的是新捕获的分值
	int check_box(int current_player)
	{
		int score = 0;
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
			{
				if (box[i][j] != 0)
					continue;
				else {
					if (line[0][i][j] != 0 && line[0][i + 1][j] != 0 && line[1][j][i] != 0 && line[1][j + 1][i] != 0)
					{
						box[i][j] = current_player;
						score++;
					}
				}
			}
		return score;
	}

	// 返回所有的合法步伐
	std::vector<Step> get_available_steps()
	{
		std::vector<Step> steps;
		int count = 0;
		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
				{
					if (line[i][j][k] == 0)
					{
						Step step;
						step.dir = i;
						step.x = j;
						step.y = k;
						steps.push_back(step);
					}
				}
		return steps;
	}


	//刷新棋盘
	void refresh_board()
	{
		//直接置零
		memset(line, 0, sizeof line);
		memset(box, 0, sizeof box);
	}

	//刷新棋盘, 与撤销操作配合使用
	void refresh_board_undo() {
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
			{
				if (box[i][j] == 0)
					continue;
				if (line[0][i][j] == 0 || line[0][i + 1][j] == 0 || line[1][j][i] == 0 || line[1][j + 1][i] == 0)
					box[i][j] = 0;
			}
	}

	// 获得当前格子(x, y)的未占领的边
	vector<Step> get_captured_line(int x, int y)
	{
		std::vector<Step> steps;
		if (line[0][x][y] == 0)
		{
			Step step;
			step.dir = 0;
			step.x = x;
			step.y = y;
			steps.push_back(step);
		}
		if (line[0][x + 1][y] == 0)
		{
			Step step;
			step.dir = 0;
			step.x = x + 1;
			step.y = y;
			steps.push_back(step);
		}
		if (line[1][y][x] == 0)
		{
			Step step;
			step.dir = 1;
			step.x = y;
			step.y = x;
			steps.push_back(step);
		}
		if (line[1][y + 1][x] == 0)
		{
			Step step;
			step.dir = 1;
			step.x = y + 1;
			step.y = x;
			steps.push_back(step);
		}
		return steps;
	}

	//获得被占领nSide边的格子数量
	int get_box_count(int nSide)
	{
		int count = 0;
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (this->get_line_count(i, j) == nSide)
					count++;
		return count;
	}

	//获得当前格子现在有几条边被占
	int get_line_count(int x, int y)
	{
		int count = 0;
		if (line[0][x][y] != 0)
			count++;
		if (line[0][x + 1][y] != 0)
			count++;
		if (line[1][y][x] != 0)
			count++;
		if (line[1][y + 1][x] != 0)
			count++;
		return count;
	}

	// 得到C型格的步伐
	vector<Step> get_dead_box_step()
	{
		vector<Step> ans;
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (get_line_count(i, j) == 3)
					ans.push_back(get_captured_line(i, j).at(0));
		return ans;
	}

	//获得一个当前棋盘的克隆体, 并且往前推演
	Board* get_new_board(int owner, int dir, int x, int y)
	{
		Board* ret = new Board();
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				ret->box[i][j] = this->box[i][j];

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					ret->line[i][j][k] = this->line[i][j][k];

		ret->set_line(owner, dir, x, y);
		if (ret->check_box(owner) > 0)
		{
			ret->next_turn = owner;
		}
		else
		{
			ret->next_turn = this->toggle_round(owner);
		}
		return ret;
	}

	//得到克隆棋盘
	Board* get_clone()
	{
		Board* ret = new Board();
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				ret->box[i][j] = this->box[i][j];

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					ret->line[i][j][k] = this->line[i][j][k];
		return ret;
	}

	// 获得棋盘中当前游戏玩家的分数
	int get_current_player_score(int current_player)
	{
		int score = 0;
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (box[i][j] == current_player)
					score++;
		return score;
	}

	// 返回当前回合的玩家的对手玩家的代表值 (本该写成static函数, 但是会发生lnk2005错误)
	int toggle_round(int turn) {
		if (turn == RED_)
			return BLUE_;
		else
			return RED_;
	}

	// 得到玩家的分数
	inline int getScore(int player) {
		return get_current_player_score(player);
	}

	//彩色打印棋盘
	void print_color_board() {
		for (int i = 0; i < 6; i++)
		{
			for (int j = 0; j < 5; j++)
			{
				if (j == 4)
					if (line[0][i][j] == RED_)
						printf("*%s--%s*\n", FAIL, RESET);
					else if (line[0][i][j] == BLUE_)
						printf("*%s--%s*\n", OKBLUE, RESET);
					else
						printf("*--*\n");
				else
					if (line[0][i][j] == RED_)
						printf("*%s--%s", FAIL, RESET);
					else if (line[0][i][j] == BLUE_)
						printf("*%s--%s", OKBLUE, RESET);
					else
						printf("*--");
			}
			if (i == 5)
				continue;

			for (int j = 0; j < 6; j++)
			{
				if (j == 5)
				{
					if (line[1][j][i] == RED_)
						printf("%s|%s", FAIL, RESET);
					else if (line[1][j][i] == BLUE_)
						printf("%s|%s", OKBLUE, RESET);
					else
						printf("|");
				}
				else if (line[1][j][i] == RED_)
				{
					printf("%s|%s", FAIL, RESET);
					if (box[i][j] == RED_)
						printf("%sr1%s", FAIL, RESET);
					else if (box[i][j] == BLUE_)
						printf("%sb2%s", OKBLUE, RESET);
					else
						printf("  ");
				}
				else if (line[1][j][i] == BLUE_)
				{
					printf("%s|%s", OKBLUE, RESET);
					if (box[i][j] == RED_)
						printf("%sr1%s", FAIL, RESET);
					else if (box[i][j] == BLUE_)
						printf("%sb2%s", OKBLUE, RESET);
					else
						printf("  ");
				}
				else
					printf("|  ");
				if (j == 5)
					printf("\n");
			}
		}
	}

	//得到安全步数的数量
	int get_safe_step_count()
	{
		vector<Step> _v;
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
			{
				int count = get_line_count(i, j);
				if (count == 0 || count == 1)
				{
					if (line[0][i][j] == 0)
					{
						Step step = { 0,i,j };
						_v.push_back(step);
					}
					if (line[0][i + 1][j] == 0)
					{
						Step step = { 0,i + 1,j };
						_v.push_back(step);
					}
					if (line[1][j][i] == 0)
					{
						Step step = { 1,j,i };
						_v.push_back(step);
					}
					if (line[1][j + 1][i] == 0)
					{
						Step step = { 1,j + 1,i };
						_v.push_back(step);
					}
				}
			}
		_v.shrink_to_fit();
		return _v.size();

	}




	inline bool isComplete()
	{
		return (get_current_player_score(RED_) + get_current_player_score(BLUE_)) == 25;
	}

	//生成hash值不考虑回合信息
	size_t get_hash()
	{
		bitset<110> bs;
		std::hash<bitset<110>> hash_gen;

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					if (line[i][j][k] != 0)
						bs.set(i * 30 + j * 5 + k);
						//bs.set((i + 1) * (j + 1) * (k + 1) - 1);

		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
			{
				if (box[i][j] == 1)
					bs.set(60 + 2 * (i * 5 + j + 1) - 2);
					//bs.set(60 + 2 * ( (i + 1) * (j + 1) ) - 2);
				else if (box[i][j] == 2)
					bs.set(60 + 2 * (i * 5 + j + 1) - 1);
					//bs.set(60 + 2 * ( (i + 1) * (j + 1) ) - 1);
			}

		return hash_gen(bs);
	}

	//生成hash值 信息全考虑 包括回合信息 格子主人信息 线的信息
	size_t get_hash(int turn)
	{
		bitset<111> bs;
		std::hash<bitset<111>> hash_gen;

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					if (line[i][j][k] != 0)
						bs.set(i * 30 + j * 5 + k);
						//bs.set((i + 1) * (j + 1) * (k + 1) - 1);

		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
			{
				if (box[i][j] == 1)
					bs.set(60 + 2 * (i * 5 + j + 1) - 2);
					//bs.set(60 + 2 * ((i + 1) * (j + 1)) - 2);
				else if (box[i][j] == 2)
					bs.set(60 + 2 * (i * 5 + j + 1) - 1);
					//bs.set(60 + 2 * ((i + 1) * (j + 1)) - 1);
			}

		if (turn == RED_)
			bs.set(110);

		return hash_gen(bs);
	}

	//只根据边的情况产生hash值 忽略格子的状态
	size_t get_line_hash()
	{
		bitset<60> bs;
		std::hash<bitset<60>> hash_gen;

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					if (line[i][j][k] != 0)
						bs.set(i * 30 + j * 5 + k);
						//bs.set((i + 1) * (j + 1) * (k + 1) - 1);
		
		return hash_gen(bs);
	}


	//根据边和格子的情况生成hash值, 但忽略格子的owner
	size_t get_bl_hash()
	{
		bitset<85> bs;
		std::hash<bitset<85>> hash_gen;

		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					if (line[i][j][k] != 0)
						bs.set(i * 30 +  j * 5 + k);
						//bs.set((i + 1) * (j + 1) * (k + 1) - 1);

		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (box[i][j] != 0)
					bs.set(60 + i * 5 + j);
					//bs.set(60 + (i + 1) * (j + 1) - 1);

		return hash_gen(bs);

	}

	//比较hash值, 忽略格子的owner
	bool cmp_bl_key(size_t key)
	{
		return this->get_bl_hash() == key;
	}

	//比较边的hash值 忽略格子的状态
	bool cmp_line_key(size_t key)
	{
		return this->get_line_hash() == key;
	}

	// 通过哈希查看棋盘是否相同
	inline bool is_same(size_t key)
	{
		return this->get_hash() == key;
	}

	// 直接传入棋盘查看是否相同
	bool is_same(Board* board)
	{
		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 6; j++)
				for (int k = 0; k < 5; k++)
					if (line[i][j][k] != board->line[i][j][k])
						return false;

		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (box[i][j] != board->box[i][j])
					return false;

		return true;
	}

	// 比较哈希值是否相同
	inline bool cmp_key(size_t key)
	{
		return is_same(key);
	}
	
	//谁赢了
	int get_winner()
	{
		return getScore(RED_) > getScore(BLUE_) ? RED_ : BLUE_;
	}


	~Board()
	{
	}
	//判断一个数为偶数
	bool mod2(int a)
	{
		if (a % 2 == 0)
			return true;
		else
			return false;
	}
	// 判断一个数为奇数
	bool mod1(int a)
	{
	   if (a % 2 == 1)
			return true;
		else
			return false;
	}

	// 3维棋盘转换为二维11x11
	void three_trans(int board[11][11])
	{
		//首先对无用点定义
		for (int i = 0; i < 11; i++)
		{
			for (int j = 0; j < 11; j++)
			{
				if (mod2(i) && mod2(j))
				{
					board[i][j] = 0;//为无用边
				}
				if (mod1(i) && mod1(j))
				{
					board[i][j] = 20;//为空格
				}
				if ((mod1(i) && mod2(j)) ||(mod1(j) && mod2(i)))
				{
					board[i][j] = 10;//为空边
				}
			}
		}
		for (int i = 0; i < 5; i++)
		{
			for (int j = 0; j < 5; j++)
			{
				int x = (i + 1) * 2 - 1;
				int y = (j + 1) * 2 - 1;
				if (box[i][j] == RED_)
				{
					board[x][y] = 2;
				}
				else if (box[i][j] == BLUE_)
				{
					board[x][y] = -2;
				}
			}
		}
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 6; j++)
			{
				for (int k = 0; k < 5; k++)
				{	
					//对行转换
					//j 偶 k 奇
					if (i == 0)
					{
						int x = 2 * j;
						int y = 2 * k + 1;
						if (line[0][j][k] == 1)
						{
							board[x][y] = 1;
						}
						else if (line[0][j][k] == 2)
						{
							board[x][y] = -1;
						}
					}
					//j 奇 k 偶
					//对列转换
					if (i == 1)
					{
						int x = 2 * k + 1;
						int y = 2 * j;
						if (line[1][j][k] == 1)
						{
							board[x][y] = 1;
						}
						else if (line[1][j][k] == 2)
						{
							board[x][y] = -1;
						}
					}

				}
			}
		}
	}

	Step xy_steps(int x, int y)
	{
		Step step{-1, -1, -1};
		//x 奇 y 偶
		if (mod1(x) && mod2(y))
		{
			step.dir = 1;
			step.x = y / 2;
			step.y = (x-1)/2;
		}
		//x 偶 y奇
		if (mod2(x) && mod1(y))
		{
			step.dir = 0;
			step.x = x / 2;
			step.y = (y - 1) / 2;
		}

		return step;
	}

	//判断步伐是否合法
	bool check_illegal(Step move) 
	{
		return (move.dir >= 0 && move.dir <= 1 && move.x >= 0 && move.x <= 5 && move.y >= 0 && move.y <= 4 && line[move.dir][move.x][move.y] == 0) ? true : false;
	}

};
